﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ColemanSoftware.Delicious.Modules.Data
{
    /// <summary>
    /// Used to validate data before it is
    /// sent to any API calls
    /// </summary>
    internal class ErrorValidator
    {
        #region PRIVATE VARIABLES

        private string _value;
        private string _name;
        private string _customMessage;
        private static string _errorCode = "";
        private static string _errors = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result code=\" " + _errorCode + "\"/>";

        #endregion

        #region PUBLIC PROERTIES

        public string Value { get { return _value; } set { _value = value; } }
        public string Name { get { return _value; } set { _value = value; } }
        public string CustomMessage { get { return _value; } set { _value = value; } }

        #endregion

        #region CONSTRUCTORS

        public ErrorValidator()
        {

        }

        public ErrorValidator(string value, string name, string customMessage = "")
        {
            this._value = value;
            this._name = name;
            this._customMessage = customMessage;
        }

        #endregion

        #region STRING VALIDATORS

        public string ValidateStrings()
        {
            return ValidateData();
        }

        public string ValidateStrings(string value, string name, string customMessage)
        {
            this._value = value;
            this._name = name;
            this._customMessage = customMessage;

            return ValidateData();
        }

        public static string ValidateBookmarkData(string title, string description, string url, DateTime dateTime)
        {
            string errors = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result code=\" ";
            string errorCode = "";

            if (String.IsNullOrEmpty(url))
            {
                errorCode = "Url is required to complete this action.";
            }
            else if (String.IsNullOrEmpty(title))
            {
                errorCode = "Title is required to complete this action.";
            }

            else if (String.IsNullOrEmpty(description))
            {
                errorCode = "Description is required to complete this action.";
            }

            else if (dateTime == DateTime.MinValue)
            {
                errorCode = "Date of entry is required to complete this action.";
            }

            if (!String.IsNullOrEmpty(errorCode))
                errors = errors + errorCode + "\"/>";

            else
                errors = "";

            return errors;
        }

        #endregion

        #region OBJECT VALIDATOR

        public static T ValidateObject<T>(Expression<Func<T>> expressionToValidate)
        {

            if (expressionToValidate.Body.NodeType == ExpressionType.Constant)
            {
                Func<T> expressionFunction = expressionToValidate.Compile();
                return expressionFunction();
            }

            else
            {
                var body = (MemberExpression)expressionToValidate.Body;

                if (GetExpressionObject(Expression.Lambda(expressionToValidate.Body)) == null)
                {
                    return default(T);
                }
                Func<T> expressionFunction = expressionToValidate.Compile();
                return expressionFunction();
            }
        }

        public static string ValidateString(Expression<Func<string>> stringer)
        {
            return ValidateObject<string>(stringer) ?? string.Empty;
        }

        #endregion

        #region PRIVATE METHODS

        #region OBJECT VALIDATION

        private static object GetMemberObject(object obj, MemberInfo memberInfo)
        {
            if (obj != null)
            {

                if (memberInfo.MemberType == MemberTypes.Property)
                {
                    PropertyInfo info = obj.GetType().GetProperty(memberInfo.Name);
                    return info.GetValue(obj, null);
                }

                else if (memberInfo.MemberType == MemberTypes.Field)
                {
                    FieldInfo fieldInfo = obj.GetType().GetField(memberInfo.Name);
                    return fieldInfo.GetValue(obj);
                }
            }

            return null;
        }


        private static object GetBaseObject(ConstantExpression constExpression, string baseObjectName)
        {
            FieldInfo fieldInfo = constExpression.Value.GetType().GetField(baseObjectName);

            if (fieldInfo != null)
            {
                return fieldInfo.GetValue(constExpression.Value);
            }

            PropertyInfo propInfo = constExpression.GetType().GetProperty(baseObjectName);

            if (propInfo != null)
            {
                return propInfo.GetValue(constExpression.Value, null);
            }
            return null;
        }

        private static object GetExpressionObject(LambdaExpression lamdaExpression)
        {
            var body = (MemberExpression)lamdaExpression.Body;

            if (body.Expression.GetType().Name == "ConstantExpression")
            {

                return GetBaseObject((ConstantExpression)body.Expression, body.Member.Name);
            }

            var baseObject = GetExpressionObject(Expression.Lambda(body.Expression));

            return GetMemberObject(baseObject, body.Member);

        }

        #endregion

        private string ValidateData()
        {
            if (String.IsNullOrEmpty(Value))
            {
                if (String.IsNullOrEmpty(CustomMessage))
                {
                    _errorCode = Name + " is required to complete this message";
                }
                else
                    _errorCode = CustomMessage;
            }

            return _errors;
        }

        #endregion
    }
}
